/*
 * Segment.java
 *
 * Created on March 27, 2007, 2:56 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.db;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import java.util.Iterator;
import java.util.UUID;
import org.atomojo.app.Nil;
import org.atomojo.app.db.DB.MediaEntryListener;
import org.restlet.data.MediaType;

/**
 *
 * @author alex
 */
public class Entry extends DBObject implements Modifiable {
   
   int id;
   int feed;
   UUID uuid;
   Timestamp created;
   Timestamp modified;
   
   /** Creates a new instance of Segment */
   public Entry(DB db,int id,int feed,UUID uuid,Timestamp created,Timestamp modified) {
      super(db);
      this.id = id;
      this.uuid = uuid;
      this.feed = feed;
      this.created = created;
      this.modified = modified;
   }

   public int getId() {
      return id;
   }

   public int getFeedId() {
      return feed;
   }
   
   public Feed getFeed() 
      throws SQLException
   {
      return db.getFeed(feed);
   }

   public UUID getUUID() {
      return uuid;
   }

   public Timestamp getCreated()
   {
      return created;
   }

   public Timestamp getEdited()
   {
      return modified;
   }
   
   public void delete(MediaEntryListener listener)
      throws SQLException
   {
      db.getJournal().recordDelete(this);
      db.deleteEntry(feed,id,listener);
   }
   
   public Iterator<EntryMedia> getResources()
      throws SQLException
   {
      return db.getResources(feed,id);
   }
   
   public Timestamp touch()
      throws SQLException
   {
      modified = new Timestamp((new Date()).getTime());
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_ENTRY_UPDATED);
         s.setTimestamp(1,modified);
         s.setInt(2,id);
         int count = s.executeUpdate();
         getFeed().touch(modified);
         return modified;
      } finally {
         db.release(s);
         db.release(dbConnection);
      }
   }
   
   public Timestamp edited() 
      throws SQLException
   {
      Timestamp t = touch();
      db.getJournal().recordModify(feed,id);
      return t;
   }
   
   public void uncategorize(Term term)
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_UNCATEGORIZE_ENTRY);
         s.setInt(1,id);
         s.setInt(2,term.getId());
         int count = s.executeUpdate();
      } finally {
         db.release(s);
         db.release(dbConnection);
      }
      
   }
   
   public void uncategorize()
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_DELETE_ENTRY_CATEGORIZATION);
         s.setInt(1,id);
         int count = s.executeUpdate();
      } finally {
         db.release(s);
         db.release(dbConnection);
      }
      
   }
   
   public void categorize(Term term)
      throws SQLException
   {
      categorize(term,null);
   }
   
   public void categorize(Term term,Object value)
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_CATEGORIZE_ENTRY);
         s.setInt(1, feed);
         s.setInt(2, id);
         s.setInt(3,term.getId());
         if (value==null || value==Nil.getInstance()) {
            s.setNull(4, Types.VARCHAR);
         } else {
            s.setString(4,value.toString());
         }
         s.executeUpdate();
      } finally {
         db.release(s);
         db.release(dbConnection);
      }
   }
   
   public EntryMedia createResource(String name,MediaType type)
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      Timestamp tstamp = new Timestamp((new Date()).getTime());
      PreparedStatement s = null;
      ResultSet r = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_RESOURCE_BY_NAME);
         s.setString(1,name);
         s.setInt(2,feed);
         r = s.executeQuery();
         if (r.next()) {
            return null;
         }
         db.release(r);
         db.release(s);
         r = null;
         s = dbConnection.getStatement(DB.STATEMENT_CREATE_RESOURCE);
         // parent feed
         s.setInt(1,feed);
         // owning entry
         s.setInt(2,id);
         // slug
         s.setString(3,name);
         // media type
         s.setString(4,type.toString());
         // created
         s.setTimestamp(5, tstamp);
         // modified
         s.setTimestamp(6, tstamp);
         int count= s.executeUpdate();
         if (count>0) {
            db.release(s);
            s = dbConnection.getStatement(DB.STATEMENT_LAST_ID_FROM_RESOURCES);
            r = s.executeQuery();
            if (r.next()) {
               int mediaId = r.getInt(1);
               return new EntryMedia(db,mediaId,feed,id,name,type,tstamp,tstamp);
            }
         }
         return null;
      } finally {
         db.release(r);
         db.release(s);
         db.release(dbConnection);
      }
   }
   
   public Iterator<TermInstance<Entry>> getTerms()
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      try {
         PreparedStatement s = dbConnection.getStatement(DB.STATEMENT_ENTRY_CATEGORIZATION);
         s.setInt(1,feed);
         s.setInt(2,id);
         return new DBIterator<TermInstance<Entry>>(s.executeQuery(),new ResultConstructor<TermInstance<Entry>>() {
            public TermInstance<Entry> newInstance(ResultSet set) 
               throws SQLException
            {
               int id = set.getInt(1);
               int term = set.getInt(2);
               String value = set.getString(3);
               return new TermInstance<Entry>(id,db.getTerm(term),Entry.this,value);
            }
         },db,dbConnection);
      } catch (SQLException ex) {
         db.release(dbConnection);
         throw ex;
      }
   }
   
   public TermInstance<Entry> getTerm(Term term)
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      ResultSet r = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_ENTRY_TERM_INSTANCE);
         s.setInt(1,feed);
         s.setInt(2,id);
         s.setInt(3,term.getId());
         r = s.executeQuery();
         if (r.next()) {
            int id = r.getInt(1);
            String value = r.getString(2);
            return new TermInstance<Entry>(id,term,Entry.this,value);
         } else {
            return null;
         }
      } finally {
         db.release(r);
         db.release(s);
         db.release(dbConnection);
      }
      
   }
   
   public boolean hasTerm(Term term,String value)
      throws SQLException
   {
      DBConnection dbConnection = db.getConnection();
      PreparedStatement s = null;
      ResultSet r = null;
      try {
         s = dbConnection.getStatement(DB.STATEMENT_ENTRY_HAS_TERM_INSTANCE);
         s.setInt(1,feed);
         s.setInt(2,id);
         s.setInt(3,term.getId());
         s.setString(4,value);
         r = s.executeQuery();
         return r.next();
      } finally {
         db.release(r);
         db.release(s);
         db.release(dbConnection);
      }
      
   }
   
}
